/*
 * Copyright (c) 2009. Silenus Consultoria, S.L.
 */
package es.silenus.detecta.olap;

import es.silenus.detecta.model.Context;
import es.silenus.detecta.model.User;

import mondrian.olap.Util;

import mondrian.spi.impl.FilterDynamicSchemaProcessor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.context.MessageSource;

import java.io.InputStream;

import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Secure schema processor.
 *
 * @author <a href="mailto:malonso@silenus-consultoria.es">Mariano Alonso</a>
 *
 * @since 14-abr-2009 19:29:49
 */
public class SecureSchemaProcessor extends FilterDynamicSchemaProcessor {
	/**
	 * Logger for this class.
	 */
	public static final Log LOG = LogFactory.getLog(SecureSchemaProcessor.class);

	/**
	 * Localization pattern.
	 */
	private static final Pattern PATTERN = Pattern.compile("(%\\{.*?\\})");

	/**
	 * Token to be parsed in mondrian schemas.
	 */
	private static final String TOKEN = "$$organization$$";

	private String extractKey(String group) {
		// removes leading '%{' and tailing '%' from the matched string
		// to obtain the required key
		return group.substring(2, group.length() - 1);
	}

	private String doRegExReplacements(String schema) {
		// As of JDK 1.5, cannot use StringBuilder - appendReplacement requires
		// the antediluvian StringBuffer.
		StringBuffer intlSchema = new StringBuffer();
		Matcher match = PATTERN.matcher(schema);
		String key;
		MessageSource i18n = Context.getMessageSource();

		Locale locale = Context.getLocale();

		while(match.find()) {
			key = extractKey(match.group());

			int start = match.start();
			int end = match.end();

			try {
				String intlProperty = i18n.getMessage(key, null, key, locale);

				if(intlProperty != null) {
					match.appendReplacement(intlSchema, intlProperty);
				}
			} catch(java.util.MissingResourceException e) {
				LOG.error("Missing resource for key [" + key + "]", e);
			} catch(java.lang.NullPointerException e) {
				LOG.error("missing resource key at substring(" + start + "," + end + ")", e);
			}
		}

		match.appendTail(intlSchema);

		return intlSchema.toString();
	}

	private int getToken() {
		User user = (User)Context.getUser();

		if(user != null) {
			if(user.getOrganization() != null) {
				return user.getOrganization().getId();
			}
		}

		return 0;
	}

	/**
	 * Modifies a Mondrian schema.
	 *
	 * @param schemaUrl the catalog URL.
	 * @param connectInfo the connection information.
	 * @param stream the stream.
	 *
	 * @return the processed schema.
	 *
	 * @throws Exception if something goes wrong.
	 */
	public String filter(final String schemaUrl, final Util.PropertyList connectInfo, final InputStream stream)
		throws Exception {
		// Process schema
		String schema = super.filter(schemaUrl, connectInfo, stream);

		// I18n process
		schema = doRegExReplacements(schema);

		// Add organization filter
		int token = getToken();
		StringBuffer result = new StringBuffer();
		int pos = 0;
		int start = schema.indexOf(TOKEN);

		while(start > -1) {
			result.append(schema.substring(pos, start));
			result.append(token);
			pos = start + TOKEN.length();
			start = schema.indexOf(TOKEN, pos);
		}

		result.append(schema.substring(pos));

		return result.toString();
	}
}
